home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / timidsrc.zip / sun_a.c < prev    next >
C/C++ Source or Header  |  1996-05-20  |  7KB  |  266 lines

  1. /* 
  2.  
  3.     TiMidity -- Experimental MIDI to WAVE converter
  4.     Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     sun_audio.c
  21.  
  22.     Functions to play sound on a Sun's /dev/audio. 
  23.  
  24.     THESE ARE UNTESTED -- If you need to make modifications to get
  25.     them to work, please send me the diffs, preferrably with a brief 
  26.     explanation of what was wrong. Thanks!
  27.  
  28. */
  29.  
  30. #include <unistd.h>
  31. #include <fcntl.h>
  32. #include <errno.h>
  33.  
  34. #include <sys/ioctl.h> 
  35.  
  36. #ifdef SOLARIS
  37.  #include <sys/audioio.h>
  38. #else
  39.  #include <sun/audioio.h>
  40. #endif
  41.  
  42. #include "config.h"
  43. #include "output.h"
  44. #include "controls.h"
  45.  
  46. static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
  47. static void close_output(void);
  48. static void output_data(int32 *buf, int32 count);
  49. static void flush_output(void);
  50. static void purge_output(void);
  51.  
  52. /* export the playback mode */
  53.  
  54. #define dpm sun_play_mode
  55.  
  56. PlayMode dpm = {
  57.   DEFAULT_RATE, PE_16BIT|PE_SIGNED,
  58.   -1,
  59.   {0,0,0,0,0}, /* no extra parameters so far */
  60.   "Sun audio device", 'd',
  61.   "/dev/audio",
  62.   open_output,
  63.   close_output,
  64.   output_data,
  65.   flush_output,
  66.   purge_output  
  67. };
  68.  
  69. /*************************************************************************/
  70. /*
  71.    Encoding will be 16-bit linear signed, unless PE_ULAW is set, in
  72.    which case it'll be 8-bit uLaw. I don't think it's worthwhile to
  73.    implement any 8-bit linear modes as the sound quality is
  74.    unrewarding. PE_MONO is honored.  */
  75.  
  76. static audio_info_t auinfo;
  77.  
  78. static int open_output(void)
  79. {
  80.   int fd, tmp, i, warnings=0;
  81.   
  82.   /* Open the audio device */
  83.  
  84. #ifdef SOLARIS
  85.   fd=open(dpm.name, O_RDWR );
  86. #else
  87.   fd=open(dpm.name, O_RDWR | O_NDELAY);
  88. #endif
  89.  
  90.   if (fd<0)
  91.     {
  92.       ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
  93.        dpm.name, sys_errlist[errno]);
  94.       return -1;
  95.     }
  96.  
  97.  
  98.   /* Does any device need byte-swapped data? Turn the bit off here. */
  99.   dpm.encoding &= ~PE_BYTESWAP;
  100.  
  101.  
  102.   AUDIO_INITINFO(&auinfo);
  103.  
  104.   if (ioctl(fd, AUDIO_GETINFO, &auinfo)<0)
  105.     { 
  106.       /* If it doesn't give info, it probably won't take requests
  107.      either. Assume it's an old device that does 8kHz uLaw only.
  108.  
  109.      Disclaimer: I don't know squat about the various Sun audio
  110.      devices, so if this is not what we should do, I'll gladly
  111.      accept modifications. */
  112.  
  113.       ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Cannot inquire %s", dpm.name);
  114.  
  115.       dpm.encoding = PE_ULAW|PE_MONO;
  116.       dpm.rate = 8000;
  117.       warnings=1;
  118.     }
  119.   else
  120.     {
  121.       ctl->cmsg(CMSG_INFO,VERB_DEBUG, 
  122.         "1. precision=%d  channels=%d  encoding=%d  sample_rate=%d",
  123.         auinfo.play.precision, auinfo.play.channels,
  124.         auinfo.play.encoding, auinfo.play.sample_rate);
  125.       ctl->cmsg(CMSG_INFO,VERB_DEBUG, 
  126.         "1. (dpm.encoding=0x%02x  dpm.rate=%d)",
  127.         dpm.encoding, dpm.rate);
  128.  
  129.  
  130.       /* Select 16-bit linear / 8-bit uLaw encoding */
  131.  
  132.       if (dpm.encoding & PE_ULAW)
  133.     {
  134.       auinfo.play.precision = 8;
  135.       auinfo.play.encoding = AUDIO_ENCODING_ULAW;
  136.     }
  137.       else
  138.     {
  139.       auinfo.play.precision = 16;
  140.       auinfo.play.encoding = AUDIO_ENCODING_LINEAR;
  141.     }
  142.       if (ioctl(fd, AUDIO_SETINFO, &auinfo)<0)
  143.     {
  144.       /* Try the other one instead */
  145.       if (dpm.encoding & PE_ULAW)
  146.         {
  147.           auinfo.play.precision = 16;
  148.           auinfo.play.encoding = AUDIO_ENCODING_LINEAR;
  149.         }
  150.       else
  151.         {
  152.           auinfo.play.precision = 8;
  153.           auinfo.play.encoding = AUDIO_ENCODING_ULAW;
  154.         }
  155.       if (ioctl(fd, AUDIO_SETINFO, &auinfo)<0)
  156.         {
  157.           ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
  158.            "%s doesn't support 16-bit linear or 8-bit uLaw samples", 
  159.            dpm.name);
  160.           close(fd);
  161.           return -1;
  162.         }
  163.       dpm.encoding ^= PE_ULAW;
  164.       ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Encoding adjusted to %s",
  165.             (dpm.encoding & PE_ULAW) ? "uLaw" : "16-bit linear");
  166.       warnings=1;
  167.     }
  168.       /* Set the other bits right. */
  169.       if (dpm.encoding & PE_ULAW)
  170.     dpm.encoding &= ~(PE_16BIT|PE_SIGNED);
  171.       else
  172.     dpm.encoding |= PE_16BIT|PE_SIGNED;
  173.  
  174.  
  175.       /* Select stereo or mono samples */
  176.  
  177.       auinfo.play.channels = (dpm.encoding & PE_MONO) ? 1 : 2;
  178.       if (ioctl(fd, AUDIO_SETINFO,&auinfo)<0)
  179.     {
  180.       auinfo.play.channels = (dpm.encoding & PE_MONO) ? 2 : 1;
  181.       if ((dpm.encoding & PE_MONO) ||
  182.           (ioctl(fd, AUDIO_SETINFO,&auinfo)<0))
  183.         {
  184.           ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 
  185.            "%s doesn't support mono or stereo samples", dpm.name);
  186.           close(fd);
  187.           return -1;
  188.         }
  189.       dpm.encoding ^= PE_MONO;
  190.       ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Sound adjusted to %sphonic", 
  191.             (dpm.encoding & PE_MONO) ? "mono" : "stereo");
  192.       warnings=1;
  193.     }
  194.  
  195.  
  196.       /* Select sampling rate */
  197.  
  198.       auinfo.play.sample_rate=dpm.rate;
  199.       if (ioctl(fd, AUDIO_SETINFO,&auinfo)<0)
  200.     {
  201.       ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
  202.             "%s doesn't support a %d Hz sample rate",
  203.             dpm.name, dpm.rate);
  204.       close(fd);
  205.       return -1;
  206.     }
  207.       /* This may be pointless -- do the Sun devices give an error if
  208.          the sampling rate can't be produced exactly? */
  209.       if (auinfo.play.sample_rate != dpm.rate)
  210.     {
  211.       dpm.rate=auinfo.play.sample_rate;
  212.       ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,
  213.             "Output rate adjusted to %d Hz", dpm.rate);
  214.       warnings=1;
  215.     }
  216.  
  217.  
  218.       ctl->cmsg(CMSG_INFO,VERB_DEBUG, 
  219.         "2. precision=%d  channels=%d  encoding=%d  sample_rate=%d",
  220.         auinfo.play.precision, auinfo.play.channels,
  221.         auinfo.play.encoding, auinfo.play.sample_rate);
  222.       ctl->cmsg(CMSG_INFO,VERB_DEBUG, 
  223.         "2. (dpm.encoding=0x%02x  dpm.rate=%d)",
  224.         dpm.encoding, dpm.rate);
  225.     }
  226.  
  227.   dpm.fd=fd;
  228.   
  229.   return warnings;
  230. }
  231.  
  232. static void output_data(int32 *buf, int32 count)
  233. {
  234.   if (!(dpm.encoding & PE_MONO)) count*=2; /* Stereo samples */
  235.   
  236.   if (dpm.encoding & PE_ULAW)
  237.     {
  238.       /* Convert to 8-bit uLaw and write out. */
  239.       s32toulaw(buf, count);
  240.       
  241.       while ((-1==write(dpm.fd, buf, count)) && errno==EINTR)
  242.     ;
  243.     }
  244.   else
  245.     {
  246.       /* Convert data to signed 16-bit PCM */
  247.       s32tos16(buf, count);
  248.       
  249.       while ((-1==write(dpm.fd, buf, count * 2)) && errno==EINTR)
  250.     ;
  251.     }
  252. }
  253.  
  254. static void close_output(void)
  255. {
  256.   close(dpm.fd);
  257. }
  258.  
  259. static void flush_output(void)
  260. {
  261. }
  262.  
  263. static void purge_output(void)
  264. {
  265. }
  266.